|
Программируем по-русски
|
Основная задача Глагола — дать человеку возможность воплощать свои мысли на языке, близком к его родному языку. Издатель Глагола
|
(*~\Глагол\Отделы\Среда~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*) (**) ОТДЕЛ СРЕДА; (*============================================================================* * НАЗНАЧЕНИЕ: среда для выполнения Глагол-приложений. * * Распределяет память под создаваемые переменные и выполняет * * уборку памяти (УП) от неиспользуемых. * * В исключительных состояниях (АвОстах) сохраняет в файл "Срез.пер" * * значения переменных у запущенных задач (из стека приложения). * * ПРИМЕЧАНИЯ: * * Свободная память запрашивается у ОС кусками. Для создаваемой * * переменной из 'куска памяти' выбирается свободный (или нарезается новый) * * участок памяти необходимого размера. Свойства участка хранятся в * * описателе участка (ОУ), расположенном до значения переменной. * * Для уборки памяти используются Данные о Видах во время выполнения (ДВ), * * которые создаются Преобразователем Глагола (ПГ). * * 'Куски памяти' организованны в кольцевой список. * * * * Размещение ДВ набора в области ПОСТоянных: * * ДВ-> вид:4; | (Данных о Видах во время выполнения) * * имя:...; } размерДВ ячеек * * ... | * * размерДВ :4; * * адр(ДВ.имя) :4; * * размер набора:4; * * ОВ-> ОВ1:4; | (Описатель Вида) * * ОВ2:4; | * * ... } ВсегоРасширений шт. * * 0 :4; | * * ... | * * 0 :4; | * *============================================================================*) ИСПОЛЬЗУЕТ ОБХОД, ОС ИЗ "..\Обмен\", Асм ИЗ "..\Иное\", Буква ИЗ "..\Иное\", Текст ИЗ "..\Числа\", Вывод ИЗ "..\Обмен\", Писать ИЗ "..\Обмен\"; ПОСТ (* размер запрашиваемого у ОС куска свободной памяти *) РазмерКуска=10000H; (* 10000H *) (* выделяется памяти перед принудительным запуском Уборки Памяти (УП) *) ЗапускУП=100*РазмерКуска; (* предельный уровень вложения доступов при записи среза переменных *) УровеньД=4; (* предельный уровень вложения задач при записи среза переменных *) УровеньЗ=30; (* количественные ограничители Преобразователя Глагола (ПГ) *) рНазвания=32; (* наибольший размер названия. Из отдела НП. *) ВсегоРасширений=10; (* наибольший уровень расширения наборов. Из отдела ЗК. *) ВсегоОтделов=64; (* количество отделов. Из отдела ВД. *) (* Программные ловушки/(аварийные остановы). Из отдела СК. *) пределыАвОст=1; номерАвОст=2; арифмАвОст=3; охранаАвОст=4; пустоАвОст=5; дляАвОст=6; выбратьАвОст=7; ответАвОст=8; проверитьАвОст=9; нольАвОст=10; бегунокАвОст=11; (* Род видов (Вид.родв). Из отдела ВД. Причём: * вЯчейка <= вЦел8 <= вЗнак <= вЦел16 <= вЦел32 <= вЦел64. *) вНеопр=0; вЯчейка=1; вКлюч=2; вЗнак=3; вЦел8=4; вЦел16=5; вЦел32=6; вЦел64=7; вВещ32=8; вВещ64=9; вМнож=10; вПЦепь=11; вПусто=12; вНет=13; вДоступ=14; вЗадача=15; вБегунок=16; вРяд=17; вОРяд=18; вНабор=19; вКон=20; (* вКон для ДВ. При изменении вКон нужно 3 преобразования с уборка:=ОТКЛ. *) ВИД (* описатель куска находится в начале каждого куска памяти, * полученного от ОС *) ОпКуска-=ДОСТУП К ВидОпКуска; ВидОпКуска=НАБОР первсв-:ЦЕЛ; (* адрес первого свободного участка *) размер-:ЦЕЛ; (* количество ячеек в куске памяти *) первуч-:ЦЕЛ; (* адрес первого участка памяти *) следку-:ОпКуска (* для организации списка *) КОН; ПОСТ РазмерОК=16; (* размер описателя куска *) ПОСТ (* Позиции свойств описателя участка (ОУ) относительно его начала. * Описатель участка предшествует каждому участку памяти, выделенному * задачей СОЗДАТЬ. Т.к. преобразователь подразумевает, что 4 ячейки, * предшествующие данным, всегда содержат адрес описателя вида (ОВ), * то <ПозУчОВ> всегда должен указывать на последнее свойство ОУ. *) ПозУчРазмера-=0; (* размер участка (если <0, то участок свободен) *) ПозУчСледСв- =4; (* адрес следующего свободного участка *) ПозУчОВ- =4; (* адрес описателя вида (ОВ) *) РазмерОУ- =8; (* размер описателя участка *) ВИД Название-=ЦЕПЬ[рНазвания]; (* Описатель Отдела (ОО) создаётся преобразователем Глагола в области * постоянных *) ОпОтдела-=ДОСТУП К ВидОпОтдела; ВидОпОтдела=НАБОР название- :Название; адрПерем- :ЦЕЛ; (* адрес переменных уровня отдела *) адрПервЗадачи- :ЦЕЛ; (* адрес первой задачи *) адрЗаПослЗадачей-:ЦЕЛ; (* адрес за последней задачей *) адрДВПерем- :ЦЕЛ; (* адрес ДВ переменных уровня отдела *) длДВПерем- :ЦЕЛ; (* длина ДВ переменных уровня отдела *) описанияЗадач- :РЯД 1 ИЗ НАБОР (* начало ряда описания задач *) нз-:ЦЕЛ; (* адрес начала задачи *) нч-:ЦЕЛ; (* адрес начала ДВ задачи *) КОН КОН; ПЕР опОтделов-:РЯД ВсегоОтделов ИЗ ЦЕЛ; (* адреса описателей отделов *) отделов- :ЦЕЛ; (* всего адресов описателей отделов *) памПослеУП:ЦЕЛ; (* выделенно ячеек памяти после прошлой УП *) уборка+ :КЛЮЧ;(* ВКЛ, если разрешена периодическая уборка памяти (УП) *) теккус- :ЦЕЛ; (* адрес текущего куска в кольцевом списке кусков *) тексвуч- :ЦЕЛ; (* адрес свободного участка <теккус> *) (* Запись среза переменных в исключительном состоянии *) ПЕР поток:Писать.Поток; (* для записи среза переменных *) отступ:ЦЕЛ; (* отступ на строке при записи среза *) уровеньд:ЦЕЛ; (* текущий уровень вложения доступов при записи среза *) (*************************************************************************** * Задачи помощники для работы с видами и переменными приложения ***************************************************************************) ЗАДАЧА ИмяИзОВ-(ов:ЦЕЛ; имя+:ЦЕПЬ); ПЕР доступИмени:ДОСТУП К Название; УКАЗ ЕСЛИ ов = 0 ТО СПИСАТЬ("ПУСТО",имя) ИНАЧЕ ОБХОД.ИзПамяти(ов-8,доступИмени); СПИСАТЬ(доступИмени^,имя) КОН КОН ИмяИзОВ; (******************************************************************************) ЗАДАЧА ОВИзПер-(пер:ЦЕЛ; ов+:ЦЕЛ); УКАЗ ЕСЛИ пер = 0 ТО ов:=0 ИНАЧЕ ОБХОД.ИзПамяти(пер-РазмерОУ+ПозУчОВ,ов) КОН КОН ОВИзПер; (* (******************************************************************************) ЗАДАЧА ИмяВИзПер-(пер:ЦЕЛ; имя+:ЦЕПЬ); ПЕР ов:ЦЕЛ; УКАЗ ОВИзПер(пер,ов); ИмяИзОВ(ов,имя) КОН ИмяВИзПер; *) (*************************************************************************** * Задачи для чтения ДВ ***************************************************************************) ЗАДАЧА ЦелИзДВ-(тч+,цел+:ЦЕЛ); (* Цель: прочитать целое число <цел> из ДВ * До: <тч> - текущий адрес чтения ДВ *) УКАЗ ОБХОД.ИзПамяти(тч,цел); УВЕЛИЧИТЬ(тч,4) КОН ЦелИзДВ; (******************************************************************************) ЗАДАЧА ЦепьИзДВ-(тч+:ЦЕЛ; цепь+:ЦЕПЬ); (* Цель: прочитать в <цепь> цепочку знаков * До: <тч> - текущий адрес чтения ДВ *) ПЕР поз:ЦЕЛ; зн:ЗНАК; УКАЗ поз:=0; ПОВТОРЯТЬ ОБХОД.ИзПамяти(тч,зн); УВЕЛИЧИТЬ(тч,2); ЕСЛИ поз < РАЗМЕР(цепь) ТО цепь[поз]:=зн КОН; УВЕЛИЧИТЬ(поз) ДО зн = 0X КОН ЦепьИзДВ; (******************************************************************************) ЗАДАЧА ВидИмяИзДВ-(тч+,вид+:ЦЕЛ; имя+:ЦЕПЬ); (* Цель: прочитать в <вид> метку ДВ, а в <имя> название ДВ * До: <тч> - текущий адрес чтения ДВ *) УКАЗ ЦелИзДВ(тч,вид); (* +вид *) ЦепьИзДВ(тч,имя) (* +имя *) КОН ВидИмяИзДВ; (******************************************************************************) ЗАДАЧА НаборИзДВ-(нп,тч+:ЦЕЛ; Обработка:ЗАДАЧА (нп,тч+:ЦЕЛ)); (* Цель: обработать ДВ набора * До: <нп> - адрес начала области переменных * <тч> - текущий адрес чтения ДВ *) ПЕР вид:ЦЕЛ; УКАЗ ОБХОД.ИзПамяти(тч,вид); ПОКА вид # вКон ВЫП Обработка(нп,тч); ОБХОД.ИзПамяти(тч,вид) КОН; УВЕЛИЧИТЬ(тч,4) (* +вид *) КОН НаборИзДВ; ЗАДАЧА^ ОтметитьВПер(нп,тч+:ЦЕЛ); (******************************************************************************) ЗАДАЧА ПропуститьДВ-(нп,тч+:ЦЕЛ); (* Цель: увеличить <тч> на столько, чтобы пропустить один ДВ * До: <нп> - адрес начала области переменных * <тч> - текущий адрес чтения ДВ *) ПЕР вид:ЦЕЛ; имя:Название; УКАЗ ВидИмяИзДВ(тч,вид,имя); (* +вид *) УВЕЛИЧИТЬ(тч,4); (* +оп *) ВЫБРАТЬ вид ИЗ вДоступ: ВидИмяИзДВ(тч,вид,имя); (* +вид *) УВЕЛИЧИТЬ(тч,4); (* +оп *) ВЫБРАТЬ вид ИЗ вНабор: УМЕНЬШИТЬ(тч,4); (* -оп *) | вРяд: УВЕЛИЧИТЬ(тч,8); (* +рслаг +чслаг *) ПропуститьДВ(нп,тч) | вОРяд: УВЕЛИЧИТЬ(тч,4); (* +рслаг *) ПропуститьДВ(нп,тч) | вБегунок: ПропуститьДВ(нп,тч) | вНеопр: КОН | вРяд: УВЕЛИЧИТЬ(тч,8); (* +рслаг +чслаг *) ПропуститьДВ(нп,тч) | вБегунок: ПропуститьДВ(нп,тч) | вНабор: НаборИзДВ(нп,тч,ПропуститьДВ) ИНАЧЕ КОН КОН ПропуститьДВ; (****************************************************************************** * Шаги по уборке памяти (УП): * а) все ранее распределённые участки памяти переводим в разряд * неиспользуемых (выставляем их размеры отрицательными); * б) отмечаем участки памяти всех размещённых переменных доступных на * данный момент как на уровне отдела так и через стек (в том числе и * через переменные доступа), как используемые (выставляем их размеры * положительными); * в) считаем, что оставшиеся участки с отрицательными размерами больше не * используются приложением, и их можно использовать для новых переменных; * г) смежные свободные участки памяти объединяем; * д) целиком свободные куски памяти возвращаем ОС. ******************************************************************************) ЗАДАЧА ОтметитьВРяду-(нпс,тч+,чслаг,рслаг:ЦЕЛ); (* Цель: отметить слагаемые ряда * До: <нпс> - адрес начала переменной слагаемого * <тч> - текущий адрес чтения ДВ * <чслаг> - число слагаемых ряда * <рслаг> - размер одного слагаемого *) ПЕР тчс:ЦЕЛ; (* текущий адрес чтения ДВ слагаемого *) вид:ЦЕЛ; (* вид слагаемых *) УКАЗ ОБХОД.ИзПамяти(тч,вид); ЕСЛИ вид В {вДоступ,вНабор,вРяд,вОРяд} ТО (* пробегаем по всем слагаемым *) ПОКА чслаг > 0 ВЫП тчс:=тч; ОтметитьВПер(нпс,тчс); УВЕЛИЧИТЬ(нпс,рслаг); УМЕНЬШИТЬ(чслаг) КОН; тч:=тчс ИНАЧЕ (* пропускаем ДВ слагаемого *) ПропуститьДВ(нпс,тч) КОН КОН ОтметитьВРяду; (******************************************************************************) ЗАДАЧА ОтмечаемУчПер(пер:ЦЕЛ):КЛЮЧ; (* Цель: искать в куче и отметить участок памяти переменной с адресом <пер> * Ответ: ВКЛ, если участок ещё не был отмечен *) ПЕР нк:ОпКуска; (* начальный кусок в кольцевом списке кусков *) тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *) уч: ЦЕЛ; (* адрес участка *) учпер: ЦЕЛ; (* адрес похожий на адрес участка переменной *) размуч:ЦЕЛ; (* размер участка *) УКАЗ ЕСЛИ пер # 0 ТО (* не ПУСТО *) учпер:=пер-РазмерОУ; (* ищем кусок, содержащий учпер *) тк:=ОБХОД.Значение(ОпКуска,теккус); нк:=тк; ПОВТОРЯТЬ ЕСЛИ (учпер >= тк.первуч) И (учпер < тк.первуч+тк.размер) ТО (* нашли кусок *) (* ищем участок *) уч:=тк.первуч; ПОКА уч <= учпер ВЫП ОБХОД.ИзПамяти(уч+ПозУчРазмера,размуч); ЕСЛИ уч = учпер ТО (* нашли участок *) ЕСЛИ размуч < 0 ТО (* он ещё не отмечен занятым *) ОБХОД.ВПамять(уч+ПозУчРазмера,-размуч); ВОЗВРАТ ВКЛ ИНАЧЕ ВОЗВРАТ ОТКЛ КОН КОН; УВЕЛИЧИТЬ(уч,МОДУЛЬ(размуч)) КОН КОН; тк:=тк.следку ДО тк = нк (* обошли всё кольцо кусков *) КОН; ВОЗВРАТ ОТКЛ КОН ОтмечаемУчПер; ЗАДАЧА^ НаборИзД-(нп,ов:ЦЕЛ; Обработка:ЗАДАЧА (нп,тч+:ЦЕЛ)); (******************************************************************************) ЗАДАЧА ОтметитьВПер(нп,тч+:ЦЕЛ); (* Цель: разбирая ДВ, найти размещённые переменные и отметить их участки памяти * До: <нп> - адрес начала области переменных * <тч> - текущий адрес чтения ДВ *) ПЕР оп:ЦЕЛ; (* адрес переменной относительно <нп> *) пп:ЦЕЛ; (* полный адрес переменной <нп>+<оп> *) ов:ЦЕЛ; (* адрес ОВ *) зд:ЦЕЛ; (* значение ДОСТУП *) вид:ЦЕЛ; (* ДВ метка вида *) имя:Название;(* имя переменной (вида) *) чслаг:ЦЕЛ; (* число слагаемых ряда *) рслаг:ЦЕЛ; (* размер одного слагаемого *) чразм:ЦЕЛ; (* число размерностей у вОРяд *) нразм:ЦЕЛ; (* номер размерности вОРяд *) длразм:ЦЕЛ; (* длина размерности вОРяд *) УКАЗ ВидИмяИзДВ(тч,вид,имя); (* +вид *) ЦелИзДВ(тч,оп); (* +оп *) ПРОВЕРИТЬ(вид # вНет); ВЫБРАТЬ вид ИЗ вДоступ: ОБХОД.ИзПамяти(нп+оп,зд); ВидИмяИзДВ(тч,вид,имя); (* +вид *) ЦелИзДВ(тч,оп); (* +оп *) ВЫБРАТЬ вид ИЗ вНабор: УМЕНЬШИТЬ(тч,4); (* -оп *) ЕСЛИ ОтмечаемУчПер(зд) ТО ОВИзПер(зд,ов); НаборИзД(зд,ов,ОтметитьВПер) КОН | вРяд: ЦелИзДВ(тч,рслаг); (* +рслаг *) ЦелИзДВ(тч,чслаг); (* +чслаг *) ЕСЛИ ОтмечаемУчПер(зд) ТО ОтметитьВРяду(зд,тч,чслаг,рслаг) ИНАЧЕ ПропуститьДВ(зд,тч) КОН | вОРяд: ЦелИзДВ(тч,рслаг); (* +рслаг *) (* по адресу ОРЯД 0-е слово содержит его размерность, * а следующие слова содержат РАЗМЕР его измерений *) ЕСЛИ ОтмечаемУчПер(зд) ТО ОБХОД.ИзПамяти(зд,чразм); чслаг:=1; нразм:=1; ПОКА нразм <= чразм ВЫП ОБХОД.ИзПамяти(зд+нразм*4,длразм); чслаг:=чслаг*длразм; УВЕЛИЧИТЬ(нразм) КОН; ОтметитьВРяду(зд+нразм*4,тч,чслаг,рслаг) ИНАЧЕ ПропуститьДВ(зд,тч) КОН | вБегунок: ПропуститьДВ(нп,тч) | вНеопр: КОН | вРяд: ЦелИзДВ(тч,рслаг); (* +рслаг *) ЦелИзДВ(тч,чслаг); (* +чслаг *) ОтметитьВРяду(нп+оп,тч,чслаг,рслаг) | вНабор: НаборИзДВ(нп,тч,ОтметитьВПер) | вБегунок: ПропуститьДВ(нп,тч) ИНАЧЕ КОН КОН ОтметитьВПер; (******************************************************************************) ЗАДАЧА НаборИзД-(нп,ов:ЦЕЛ; Обработка:ЗАДАЧА (нп,тч+:ЦЕЛ)); (* Цель: найти размещённые переменные набора и обработать их * До: <нп> - адрес начала области переменных *) ПЕР тч: ЦЕЛ; (* текущий адрес для чтения *) вч: ЦЕЛ; (* всего ячеек для чтения *) кч: ЦЕЛ; (* последний адрес для чтения *) ур: ЦЕЛ; (* уровень расширения набора *) ово:ЦЕЛ; (* адрес описателя вида основания *) имя:Название; УКАЗ кч:=ов-12; ОБХОД.ИзПамяти(кч,вч); ИмяИзОВ(ов,имя); ЕСЛИ вч >= 0 ТО тч:=кч-вч; (* просмотр ДВ в нашем наборе *) ПОКА тч < кч ВЫП Обработка(нп,тч) КОН; (* просмотр ДВ в основаниях нашего набора *) ур:=ВсегоРасширений-1; КОЛЬЦО ЕСЛИ ур <= 0 ТО ВЫХОД КОН; ОБХОД.ИзПамяти(ов+ур*4,ово); ЕСЛИ ово # 0 ТО (* берём предпоследний ОВО, т.к. в последнем ОВО * хранится адрес своего ОВ *) ОБХОД.ИзПамяти(ов+(ур-1)*4,ово); НаборИзД(нп,ово,Обработка); ВЫХОД КОН; УМЕНЬШИТЬ(ур) КОН КОН КОН НаборИзД; (******************************************************************************) ЗАДАЧА ОтметитьВЗадаче(нп,тч:ЦЕЛ); (* Цель: разбирает ДВ задачи, находит размещённые переменные и отмечает их * участки памяти как занятые * До: <нп> - адрес начала переменных задачи (регистр EBP при работе задачи) * <тч> - текущий адрес чтения ДВ *) ПЕР вид:ЦЕЛ; (* ДВ метка вида *) имя:Название; УКАЗ ЦепьИзДВ(тч,имя); КОЛЬЦО ЦелИзДВ(тч,вид); (* +вид *) ЕСЛИ вид = вКон ТО ВЫХОД КОН; УМЕНЬШИТЬ(тч,4); (* -вид *) ОтметитьВПер(нп,тч) КОН КОН ОтметитьВЗадаче; (******************************************************************************) ЗАДАЧА ОтметитьВОтделе(адрОО:ЦЕЛ); (* Цель: разбирает ДВ отдела, находит размещённые переменные и отмечает их * участки памяти как занятые *) ПЕР тч:ЦЕЛ; (* текущий адрес для чтения *) кч:ЦЕЛ; (* запоследний адрес для чтения *) оо:ОпОтдела; (* Описатель Отдела *) УКАЗ оо:=ОБХОД.Значение(ОпОтдела,адрОО); тч:=оо.адрДВПерем; кч:=тч+оо.длДВПерем; ПОКА тч < кч ВЫП ОтметитьВПер(оо.адрПерем,тч) КОН КОН ОтметитьВОтделе; (******************************************************************************) ЗАДАЧА УдалитьСвКуски(); (* Цель: найти полностью свободные куски памяти и возвратить их в ОС * Прим: из кольцевого списка удобно удалять последующий кусок * После: <теккус> - адрес начального куска в кольцевом списке кусков * <тексвуч> - адрес первого свободного участка <теккус> *) ПЕР тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *) ск:ОпКуска; (* следующий кусок в кольцевом списке кусков *) нк:ОпКуска; (* начальный неудаляемый кусок *) размсв:ЦЕЛ; (* размер первого свободного участка в <ск> *) удалёнск:КЛЮЧ; (* если был удалён <ск>, то ВКЛ *) адрес:ЦЕЛ; (* адрес памяти, возвращаемой в ОС *) УКАЗ тк:=ОБХОД.Значение(ОпКуска,теккус); ск:=тк.следку; нк:=ПУСТО; ПОВТОРЯТЬ удалёнск:=ОТКЛ; ЕСЛИ ск.первсв # 0 ТО ОБХОД.ИзПамяти(ск.первсв+ПозУчРазмера,размсв); ЕСЛИ ск.размер = -размсв ТО (* весь кусок свободен *) адрес:=ОБХОД.Значение(ЦЕЛ,ск); ЕСЛИ ск = тк ТО (* был последним куском в списке *) ОС.ОтдатьПамять(адрес); теккус:=0; ВОЗВРАТ КОН; (* удаляем <ск> из кольцевого списка *) ск:=ск.следку; тк.следку:=ск; удалёнск:=ВКЛ; ОС.ОтдатьПамять(адрес) КОН КОН; ЕСЛИ НЕ удалёнск ТО ЕСЛИ нк = ПУСТО ТО нк:=ск КОН; (* продвигаем <тк> и <ск> *) тк:=ск; ск:=тк.следку КОН ДО ск = нк; (* обошли всё кольцо кусков *) теккус:=ОБХОД.Значение(ЦЕЛ,нк); тексвуч:=нк.первсв КОН УдалитьСвКуски; (* (******************************************************************************) ЗАДАЧА ПроверитьКучу-(); (* Цель: проверить строение всей кучи *) ПЕР нк:ОпКуска; (* начальный кусок в кольцевом списке кусков *) тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *) послуч:ЦЕЛ; (* адрес запоследнего участок в куске *) уч: ЦЕЛ; (* адрес текущего участка *) св: ЦЕЛ; (* адрес свободного участка *) размуч:ЦЕЛ; (* размер <уч> *) УКАЗ ЕСЛИ теккус = 0 ТО ВОЗВРАТ КОН; тк:=ОБХОД.Значение(ОпКуска,теккус); нк:=тк; ПОВТОРЯТЬ ПРОВЕРИТЬ((тк.размер > 0) И ((тк.размер+РазмерОК) ОСТАТОК РазмерКуска = 0) И (тк.первуч = (ОБХОД.Значение(ЦЕЛ,тк)+РазмерОК))); уч:=тк.первуч; послуч:=тк.первуч+тк.размер; св:=тк.первсв; ПОКА уч < послуч ВЫП ОБХОД.ИзПамяти(уч+ПозУчРазмера,размуч); ЕСЛИ размуч < 0 ТО (* свободный участок *) ПРОВЕРИТЬ(уч = св); ОБХОД.ИзПамяти(св+ПозУчСледСв,св); УВЕЛИЧИТЬ(уч,-размуч) ИНАЧЕ УВЕЛИЧИТЬ(уч,размуч) КОН КОН; ПРОВЕРИТЬ((уч = послуч) И (св = 0)); тк:=тк.следку ДО тк = нк (* обошли всё кольцо кусков *) КОН ПроверитьКучу; *) (******************************************************************************) ЗАДАЧА GetEBP-():ЦЕЛ; (* Цель: возвратить значение регистра EBP вызвавшей задаче *) ПЕР п:ЦЕЛ; УКАЗ п:=ОБХОД.ПолучитьАдрес(п)+4+4; (* после 'п': свой EBP, пред. EBP, пред. EIP *) ОБХОД.ИзПамяти(п,п); ВОЗВРАТ п КОН GetEBP; (******************************************************************************) ЗАДАЧА НайтиДВЗадачи-(адр,но+,нч+:ЦЕЛ); (* Цель: найти задачу и её ДВ по внутреннему адресу задачи <адр> * После: <тч> - начальный адрес чтения ДВ * <но> - номер отдела, в котором находится задача или 0 *) ПЕР оо:ОпОтдела;(* Описатель Отдела *) оз:ЦЕЛ; (* адрес Описания Задачи *) нз:ЦЕЛ; (* адрес начала задачи *) УКАЗ но:=0; ПОКА но < отделов ВЫП оо:=ОБХОД.Значение(ОпОтдела,опОтделов[но]); ЕСЛИ (адр >= оо.адрПервЗадачи) И (адр < оо.адрЗаПослЗадачей) ТО (* нашли отдел *) оз:=ОБХОД.ПолучитьАдрес(оо.описанияЗадач[0].нз); КОЛЬЦО ОБХОД.ИзПамяти(оз,нз); ЕСЛИ нз <= адр ТО (* нашли задачу *) ОБХОД.ИзПамяти(оз+4,нч); ВОЗВРАТ КОН; УВЕЛИЧИТЬ(оз,8) (* следующая запись *) КОН; КОН; УВЕЛИЧИТЬ(но) КОН; КОН НайтиДВЗадачи; (******************************************************************************) ЗАДАЧА Уборка-(); (* Цель: найти и объединить неиспользуемые участки памяти * После: <теккус> - адрес начального куска в кольцевом списке кусков * <тексвуч> - адрес первого свободного участка <теккус> *) ПЕР но: ЦЕЛ; (* номер отдела *) св: ЦЕЛ; (* адрес группы свободных участков *) размуч:ЦЕЛ; (* размер участка *) послуч:ЦЕЛ; (* адрес первой ячейки после куска *) размсв:ЦЕЛ; (* размер группы свободных участков *) предсв:ЦЕЛ; (* адрес предыдущего свободного участка *) EBP: ЦЕЛ; (* значение машинного регистра *) EIP: ЦЕЛ; (* значение машинного регистра *) тч: ЦЕЛ; (* текущий адрес чтения ДВ *) нк:ОпКуска; (* начальный кусок в кольцевом списке кусков *) тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *) уч: ЦЕЛ; (* адрес текущего участка *) ц0: ЦЕЛ; (* целый 0 *) УКАЗ ЕСЛИ теккус = 0 ТО ВОЗВРАТ КОН; ц0:=0; (* размеры всех участков делаем отрицательными (как у свободных) *) нк:=ОБХОД.Значение(ОпКуска,теккус); тк:=нк; ПОВТОРЯТЬ уч:=тк.первуч; послуч:=уч+тк.размер; ПОКА уч < послуч ВЫП ОБХОД.ИзПамяти(уч+ПозУчРазмера,размуч); размуч:=МОДУЛЬ(размуч); ОБХОД.ВПамять(уч+ПозУчРазмера,-размуч); УВЕЛИЧИТЬ(уч,размуч) КОН; тк:=тк.следку ДО тк = нк; (* обошли всё кольцо кусков *) (* отмечаем переменные всех отделов *) но:=0; ПОКА но < отделов ВЫП ОтметитьВОтделе(опОтделов[но]); УВЕЛИЧИТЬ(но) КОН; (* отмечаем переменные работающих задач (переменные стека) *) EBP:=GetEBP(); КОЛЬЦО ОБХОД.ИзПамяти(EBP+4,EIP); (* EIP вызвавшей задачи *) ОБХОД.ИзПамяти(EBP,EBP); (* EBP вызвавшей задачи *) ЕСЛИ EBP = 0 ТО ВЫХОД КОН; (* вызвавшая задача - Пускач.^Запуск *) НайтиДВЗадачи(EIP,но,тч); ЕСЛИ но < отделов ТО ОтметитьВЗадаче(EBP,тч) КОН КОН; (* объединяем смежные свободные участки, и строим для них список *) тк:=нк; ПОВТОРЯТЬ св:=0; предсв:=0; уч:=тк.первуч; послуч:=уч+тк.размер; ПОКА уч < послуч ВЫП (* по всем участкам куска *) ОБХОД.ИзПамяти(уч+ПозУчРазмера,размуч); ЕСЛИ размуч < 0 ТО (* для свободного участка *) ЕСЛИ св = 0 ТО (* если это начало области *) св:=уч; (* сохраним её адрес *) размсв:=размуч (* и начнем её замерять *) ИНАЧЕ (* продолжение области *) УВЕЛИЧИТЬ(размсв,размуч) (* замеряем её дальше *) КОН АЕСЛИ св # 0 ТО (* конец области *) (* заранее обнуляем весь участок *) Асм.ОбнулитьПамять(св+РазмерОУ,-размсв-РазмерОУ); (* выставляем окончательный размер области *) ОБХОД.ВПамять(св+ПозУчРазмера,размсв); ОБХОД.ВПамять(св+ПозУчСледСв,ц0); ЕСЛИ предсв = 0 ТО (* первая область *) тк.первсв:=св (* обновляем первсв в куске *) ИНАЧЕ (* уже была область *) (* то выставляем у неё ссылку на нашу область *) ОБХОД.ВПамять(предсв+ПозУчСледСв,св) КОН; предсв:=св; (* готовимся к следующей области *) св:=0 КОН; УВЕЛИЧИТЬ(уч,МОДУЛЬ(размуч)) КОН; (* такая же обработка в конце куска *) ЕСЛИ св # 0 ТО (* конец области *) (* заранее обнуляем весь участок *) Асм.ОбнулитьПамять(св+РазмерОУ,-размсв-РазмерОУ); (* выставляем окончательный размер области *) ОБХОД.ВПамять(св+ПозУчРазмера,размсв); ОБХОД.ВПамять(св+ПозУчСледСв,ц0); ЕСЛИ предсв = 0 ТО (* первая область *) тк.первсв:=св (* записываем ссылку в куске *) ИНАЧЕ (* уже была предобласть *) (* то выставляем у неё ссылку на область *) ОБХОД.ВПамять(предсв+ПозУчСледСв,св) КОН КОН; тк:=тк.следку ДО тк = нк; (* обошли всё кольцо кусков *) УдалитьСвКуски(); памПослеУП:=0 КОН Уборка; (******************************************************************************) ЗАДАЧА НаходимСвобУч(размер:ЦЕЛ):КЛЮЧ; (* Цель: искать по всем кускам участок памяти не меньше <размер> ячеек * Прим: если находит такой участок, то возвращает ВКЛ и * После: <теккус> - адрес куска из кольцевого списка * <тексвуч> - адрес свободного участка <теккус> *) ПЕР тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *) нк:ОпКуска; (* кусок с которого начинается поиск *) нсвуч: ЦЕЛ; (* адрес свободного участка с которого начинается поиск *) размсв:ЦЕЛ; (* размер свободного <тексвуч> *) УКАЗ ЕСЛИ теккус = 0 ТО ВОЗВРАТ ОТКЛ КОН; тк:=ОБХОД.Значение(ОпКуска,теккус); нк:=тк; нсвуч:=тексвуч; ПОВТОРЯТЬ ПОКА тексвуч = 0 ВЫП (* кончился кусок *) тк:=тк.следку; теккус:=ОБХОД.Значение(ЦЕЛ,тк); тексвуч:=тк.первсв; ЕСЛИ (тк = нк) И (тексвуч = нсвуч) ТО (* обошли все участки *) ВОЗВРАТ ОТКЛ КОН КОН; ОБХОД.ИзПамяти(тексвуч+ПозУчРазмера,размсв); ЕСЛИ -размсв >= размер ТО ВОЗВРАТ ВКЛ КОН; ОБХОД.ИзПамяти(тексвуч+ПозУчСледСв,тексвуч) ДО (тк = нк) И (тексвуч = нсвуч); (* обошли все участки *) ВОЗВРАТ ОТКЛ КОН НаходимСвобУч; (******************************************************************************) ЗАДАЧА СоздатьКусок(размер:ЦЕЛ); (* Цель: запрос у ОС нового куска памяти с полезным размером <размер> * После: <теккус> - адрес нового текущего куска в кольцевом списке кусков * <тексвуч> - адрес первого (и единственного) участка <теккус> *) ПЕР нк:ОпКуска; (* новый кусок в кольцевом списке кусков *) тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *) ц0: ЦЕЛ; (* целый 0 *) УКАЗ ц0:=0; тк:=ОБХОД.Значение(ОпКуска,теккус); УВЕЛИЧИТЬ(размер,РазмерОК); УВЕЛИЧИТЬ(размер,(-размер) ОСТАТОК РазмерКуска); (* выравнивание на РазмерКуска *) теккус:=ОС.ВзятьПамять(размер); ПРОВЕРИТЬ(теккус # 0); нк:=ОБХОД.Значение(ОпКуска,теккус); тексвуч:=теккус+РазмерОК; (* оставляем место для <нк> *) УМЕНЬШИТЬ(размер,РазмерОК); нк.размер:=размер; нк.первуч:=тексвуч; нк.первсв:=тексвуч; ОБХОД.ВПамять(тексвуч+ПозУчСледСв,ц0); ОБХОД.ВПамять(тексвуч+ПозУчРазмера,-размер); (* вставляем новый кусок в кольцевой список после текущего куска *) ЕСЛИ тк # ПУСТО ТО нк.следку:=тк.следку; тк.следку:=нк ИНАЧЕ нк.следку:=нк КОН КОН СоздатьКусок; (******************************************************************************) ЗАДАЧА СоздатьУч(размер:ЦЕЛ):ЦЕЛ; (* Цель: создать участок с размером <размер> (в конце <тексвуч> * или весь <тексвуч>) и возвратить его адрес * До: <теккус> - адрес текущего куска в кольцевом списке кусков * <тексвуч> - адрес достаточно большого свободного участка в <теккус> * После: <тексвуч> - бывший или следующий адрес свободного участка *) ПЕР предсв:ЦЕЛ; (* адрес предыдущего свободного участка *) размсв:ЦЕЛ; (* размер свободного участка *) тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *) уч: ЦЕЛ; (* адрес свободного участка *) создуч:ЦЕЛ; (* адрес созданного участка *) УКАЗ ОБХОД.ИзПамяти(тексвуч+ПозУчРазмера,размсв); размсв:=-размсв; (* размер будет положительным *) ЕСЛИ размсв > размер+РазмерОУ+4 ТО (* забираем хвост у <тексвуч> *) УМЕНЬШИТЬ(размсв,размер); ОБХОД.ВПамять(тексвуч+ПозУчРазмера,-размсв); создуч:=тексвуч+размсв; ОБХОД.ВПамять(создуч+ПозУчРазмера,размер); (* ссылки в списке свободных участков остались те же *) ИНАЧЕ (* забираем целиком <тексвуч> *) создуч:=тексвуч; ОБХОД.ВПамять(создуч+ПозУчРазмера,размсв); (* новый <тексвуч> *) ОБХОД.ИзПамяти(создуч+ПозУчСледСв,тексвуч); (* удаляем <создуч> из списка свободных участков *) тк:=ОБХОД.Значение(ОпКуска,теккус); ЕСЛИ создуч = тк.первсв ТО (* это <первсв> в куске *) тк.первсв:=тексвуч ИНАЧЕ предсв:=тк.первсв; (* ищем предыдущий свободный участок *) уч:=предсв; ПОКА уч # создуч ВЫП предсв:=уч; ОБХОД.ИзПамяти(уч+ПозУчСледСв,уч) КОН; ОБХОД.ВПамять(предсв+ПозУчСледСв,тексвуч) КОН КОН; ВОЗВРАТ создуч КОН СоздатьУч; (*************************************************************************** * Задачи, вызываемые из приложения неявным образом ***************************************************************************) ЗАДАЧА Создать-(ов,размер,адрес+:ЦЕЛ); (* Цель: поддержка встроенных в Глагол задач: * СОЗДАТЬ(<пер>+:вид) - для наборов и рядов * СОЗДАТЬ(<пер>+:вид; <ДЛ1>,...,<ДЛn>:ЦЕЛ) - для открытых рядов * До: <ов> - описатель вида переменной <пер> * для рядов и открытых рядов <ов> = 0 * <размер> - размер данных у <пер> * для открытых рядов <размер> = 4+n*4+<ДЛ1>*...*<ДЛn> * После: <адрес> - адрес выделенной памяти заполненной 0-ми, * четыре ячейки перед <адрес> всегда содержат <ов> *) ПЕР уч:ЦЕЛ; (* адрес свободного участка *) УКАЗ УВЕЛИЧИТЬ(размер,РазмерОУ); УВЕЛИЧИТЬ(размер,(-размер) ОСТАТОК 4); (* выравнивание *) ЕСЛИ НЕ НаходимСвобУч(размер) ТО ЕСЛИ уборка И (памПослеУП >= ЗапускУП) ТО Уборка(); ЕСЛИ НЕ НаходимСвобУч(размер) ТО СоздатьКусок(размер) КОН ИНАЧЕ СоздатьКусок(размер) КОН КОН; ЕСЛИ размер < РазмерКуска ТО УВЕЛИЧИТЬ(памПослеУП,размер) КОН; уч:=СоздатьУч(размер); ОБХОД.ВПамять(уч+ПозУчОВ,ов); адрес:=уч+РазмерОУ КОН Создать; (******************************************************************************) ЗАДАЧА Присоединить-(адрОО:ЦЕЛ); (* Цель: присоединить к среде отдел, где <адрОО> адрес описателя отдела, * расположенного в постоянной области кода * Прим: вызывается однократно для каждого отдела при запуске приложения *) УКАЗ ПРОВЕРИТЬ(отделов < ВсегоОтделов); опОтделов[отделов]:=адрОО; УВЕЛИЧИТЬ(отделов) КОН Присоединить; (*************************************************************************** * Запись среза значений переменных работающих задач в исключительном состоянии ***************************************************************************) ЗАДАЧА^ Пер(нп,тч+:ЦЕЛ); (******************************************************************************) ЗАДАЧА Цепь(цепь-:ЦЕПЬ); УКАЗ Писать.Цепь(поток,цепь) КОН Цепь; (******************************************************************************) ЗАДАЧА Цел(описание-:ЦЕПЬ; ц:ШИРЦЕЛ); УКАЗ Писать.ЧЦел(поток,описание,ц,0,0,0); КОН Цел; (******************************************************************************) ЗАДАЧА Вещ(описание-:ЦЕПЬ; в:ШИРВЕЩ); УКАЗ Писать.ЧВещ(поток,описание,в,0,0,0); КОН Вещ; (******************************************************************************) ЗАДАЧА Ряд(нпс,тч+,чслаг,рслаг:ЦЕЛ); (* Цель: выписать значения всех слагаемых ряда * До: <нпс> - адрес начала переменной слагаемого * <тч> - текущий адрес чтения ДВ * <чслаг> - число слагаемых в ряду * <рслаг> - размер одного слагаемого *) ПЕР зз:ЗНАК; (* ЗНАК значение *) тчс:ЦЕЛ; (* текущий адрес чтения ДВ слагаемого *) вид:ЦЕЛ; (* ДВ метка вида *) имя:Название;(* название переменной (вида) *) УКАЗ тчс:=тч; ВидИмяИзДВ(тчс,вид,имя); ЕСЛИ вид = вЗнак ТО (* цепочка знаков *) Цепь('"'); КОЛЬЦО ЕСЛИ чслаг <= 0 ТО ВЫХОД КОН; ОБХОД.ИзПамяти(нпс,зз); ЕСЛИ зз = 0X ТО ВЫХОД АЕСЛИ ((зз >= ' ') И (зз <= '#007F')) ИЛИ Буква.Известная(зз) ТО Цел("%c",ВЦЕЛ(зз)) ИНАЧЕ Цел("##%.4x",ВЦЕЛ(зз)) КОН; УВЕЛИЧИТЬ(нпс,рслаг); УМЕНЬШИТЬ(чслаг) КОН; Цепь('"'); тч:=тчс+4 (* +оп *) ИНАЧЕ УВЕЛИЧИТЬ(отступ,2); ПОКА чслаг > 0 ВЫП тчс:=тч; Пер(нпс,тчс); УВЕЛИЧИТЬ(нпс,рслаг); УМЕНЬШИТЬ(чслаг) КОН; УМЕНЬШИТЬ(отступ,2); тч:=тчс КОН; КОН Ряд; (******************************************************************************) ЗАДАЧА ИмяЗадачи(аз,тч+:ЦЕЛ); (* Цель: выписать полное название задачи * До: <аз> - произвольный адрес внутри кода задачи * <тч> - текущий адрес чтения ДВ *) ПЕР оо:ОпОтдела; (* описатель отдела *) но:ЦЕЛ; (* № отдела *) имя:Название;(* имя задачи *) УКАЗ НайтиДВЗадачи(аз,но,тч); ЕСЛИ но < отделов ТО оо:=ОБХОД.Значение(ОпОтдела,опОтделов[но]); Цепь(оо.название); Цепь("."); ЦепьИзДВ(тч,имя); Цепь(имя) ИНАЧЕ Цепь("ПУСТО"); тч:=0 КОН КОН ИмяЗадачи; (******************************************************************************) ЗАДАЧА Пер(нп,тч+:ЦЕЛ); (* Цель: выписать значение переменной * До: <нп> - адрес начала области переменных * <тч> - текущий адрес чтения ДВ *) ПЕР оп:ЦЕЛ; (* адрес переменной относительно <нп> *) пп:ЦЕЛ; (* полный адрес переменной <нп>+<оп> *) ов:ЦЕЛ; (* адрес ОВ *) зз:ЗНАК; (* ЗНАК значение *) ц8:ОБХОД.Цел8; (* Цел8 значение *) ц16:ОБХОД.Цел16; (* Цел16 значение *) ц32:ОБХОД.Цел32; (* Цел32 значение *) ц64:ОБХОД.Цел64; (* Цел64 значение *) в32:ОБХОД.Вещ32; (* Вещ32 значение *) в64:ОБХОД.Вещ64; (* Вещ64 значение *) ц :ЦЕЛ; (* ЦЕЛ значение *) дз:ЦЕЛ; (* ДОСТУП значение *) тб:ЦЕЛ; (* текущее значение бегунка *) нб:ЦЕЛ; (* начало ряда бегунка *) кб:ЦЕЛ; (* конец ряда бегунка *) вид:ЦЕЛ; (* ДВ метка вида *) имя:Название;(* название переменной (вида) *) чслаг:ЦЕЛ; (* число слагаемых ряда *) рслаг:ЦЕЛ; (* размер одного слагаемого *) чразм:ЦЕЛ; (* число размерностей у вОРяд *) нразм:ЦЕЛ; (* номер размерности вОРяд *) длразм:ЦЕЛ; (* длина размерности вОРяд *) УКАЗ ВидИмяИзДВ(тч,вид,имя); (* +вид *) ЦелИзДВ(тч,оп); (* +оп *) пп:=нп+оп; Цел("^%*",отступ); Цепь(имя); Цепь("="); ВЫБРАТЬ вид ИЗ вЯчейка: ОБХОД.ИзПамяти(пп,ц8); ц:=ц8; ЕСЛИ ц < 0 ТО УВЕЛИЧИТЬ(ц,100H) КОН; Цел("%.2xH",ц) | вКлюч: ОБХОД.ИзПамяти(пп,ц8); Цел("%d",ц8) | вЗнак: ОБХОД.ИзПамяти(пп,зз); ЕСЛИ ((зз >= ' ') И (зз <= '#007F')) ИЛИ Буква.Известная(зз) ТО Цел("'%c'",ВЦЕЛ(зз)) ИНАЧЕ Цел("%.4xX",ВЦЕЛ(зз)) КОН | вЦел8: ОБХОД.ИзПамяти(пп,ц8); Цел("%d",ц8) | вЦел16: ОБХОД.ИзПамяти(пп,ц16); Цел("%d",ц16) | вЦел32: ОБХОД.ИзПамяти(пп,ц32); Цел("%d",ц32) | вЦел64: ОБХОД.ИзПамяти(пп,ц64); Цел("%d",ц64) | вВещ32: ОБХОД.ИзПамяти(пп,в32); Вещ("%g",в32) | вВещ64: ОБХОД.ИзПамяти(пп,в64); Вещ("%g",в64) | вМнож: ОБХОД.ИзПамяти(пп,ц32); Цел("%.8xH",ц32) | вЗадача: ОБХОД.ИзПамяти(пп,дз); ИмяЗадачи(дз,дз) | вБегунок: ОБХОД.ИзПамяти(пп+0,тб); ОБХОД.ИзПамяти(пп+4,нб); ОБХОД.ИзПамяти(пп+8,кб); ЕСЛИ уровеньд >= УровеньД ТО ПропуститьДВ(нп,тч) АЕСЛИ тб = 0 ТО Цепь("ПУСТО"); ПропуститьДВ(нп,тч) АЕСЛИ тб < нб ТО (* работает, если ВКЛ проверки *) Цепь("до ряда"); ПропуститьДВ(нп,тч) АЕСЛИ тб >= кб ТО (* работает, если ВКЛ проверки *) Цепь("после ряда"); ПропуститьДВ(нп,тч) ИНАЧЕ УВЕЛИЧИТЬ(уровеньд); УВЕЛИЧИТЬ(отступ,2); Пер(тб,тч); УМЕНЬШИТЬ(отступ,2); УМЕНЬШИТЬ(уровеньд) КОН; | вДоступ: ОБХОД.ИзПамяти(пп,дз); ВидИмяИзДВ(тч,вид,имя); (* +вид *) ЦелИзДВ(тч,оп); (* +оп *) ВЫБРАТЬ вид ИЗ вНабор: УМЕНЬШИТЬ(тч,4); (* -оп *) ЕСЛИ дз = 0 ТО Цепь("ПУСТО") ИНАЧЕ ЕСЛИ уровеньд < УровеньД ТО УВЕЛИЧИТЬ(уровеньд); ОВИзПер(дз,ов); УВЕЛИЧИТЬ(отступ,2); НаборИзД(дз,ов,Пер); УМЕНЬШИТЬ(отступ,2); УМЕНЬШИТЬ(уровеньд) КОН КОН | вНеопр: Цепь("ОБХОД.Доступ") | вРяд: ЦелИзДВ(тч,рслаг); (* +рслаг *) ЦелИзДВ(тч,чслаг); (* +чслаг *) ЕСЛИ (дз = 0) ИЛИ (уровеньд >= УровеньД) ТО ЕСЛИ дз = 0 ТО Цепь("ПУСТО") КОН; ПропуститьДВ(нп,тч) ИНАЧЕ УВЕЛИЧИТЬ(уровеньд); Ряд(дз,тч,чслаг,рслаг); УМЕНЬШИТЬ(уровеньд) КОН | вОРяд: ЦелИзДВ(тч,рслаг); (* +рслаг *) (* по адресу ОРЯД 0-е слово содержит его размерность, * а следующие слова содержат РАЗМЕРы его измерений *) ЕСЛИ (дз = 0) ИЛИ (уровеньд >= УровеньД) ТО ЕСЛИ дз = 0 ТО Цепь("ПУСТО") КОН; ПропуститьДВ(нп,тч) ИНАЧЕ УВЕЛИЧИТЬ(уровеньд); ОБХОД.ИзПамяти(дз,чразм); чслаг:=1; нразм:=1; ПОКА нразм <= чразм ВЫП ОБХОД.ИзПамяти(дз+нразм*4,длразм); чслаг:=чслаг*длразм; УВЕЛИЧИТЬ(нразм) КОН; Ряд(дз+нразм*4,тч,чслаг,рслаг); УМЕНЬШИТЬ(уровеньд) КОН | вБегунок: ПропуститьДВ(нп,тч) КОН | вРяд: ЦелИзДВ(тч,рслаг); (* +рслаг *) ЦелИзДВ(тч,чслаг); (* +чслаг *) Ряд(пп,тч,чслаг,рслаг) | вНабор: УВЕЛИЧИТЬ(отступ,2); НаборИзДВ(нп,тч,Пер); УМЕНЬШИТЬ(отступ,2) ИНАЧЕ Цепь("НЕИЗВЕСТНЫЙ вид") КОН КОН Пер; (******************************************************************************) ЗАДАЧА ПерСтека(EBP:ЦЕЛ); ПЕР EIP:ЦЕЛ; (* значение машинного регистра *) тч: ЦЕЛ; (* текущий адрес чтения ДВ *) вид:ЦЕЛ; (* ДВ метка вида *) уровеньз:ЦЕЛ;(* уровень вложения задач *) УКАЗ уровеньз:=0; КОЛЬЦО ЕСЛИ уровеньз >= УровеньЗ ТО ВЫХОД КОН; ОБХОД.ИзПамяти(EBP+4,EIP); (* EIP вызвавшей задачи *) ОБХОД.ИзПамяти(EBP,EBP); (* EBP вызвавшей задачи *) ЕСЛИ EBP = 0 ТО ВЫХОД КОН; (* вызвавшая задача - Пускач._Nachalo *) Цепь("^^Переменные задачи "); ИмяЗадачи(EIP,тч); ЕСЛИ тч # 0 ТО отступ:=2; КОЛЬЦО ЦелИзДВ(тч,вид); (* +вид *) ЕСЛИ вид = вКон ТО ВЫХОД КОН; УМЕНЬШИТЬ(тч,4); (* -вид *) Пер(EBP,тч) КОН КОН; УВЕЛИЧИТЬ(уровеньз) КОН КОН ПерСтека; (******************************************************************************) ЗАДАЧА Ловушка-(адрОО,кодстрока:ЦЕЛ); (* Цель: ловушка исключений *) ПЕР EBP:ЦЕЛ; код,строка:ЦЕЛ; оо:ОпОтдела; текст:ЦЕПЬ[100]; УКАЗ EBP:=GetEBP(); оо:=ОБХОД.Значение(ОпОтдела,адрОО); код:=кодстрока ОСТАТОК 10000H; строка:=кодстрока ДЕЛИТЬ 10000H; Вывод.Цепь('^Сработала ловушка в отделе "'); Вывод.Цепь(оо.название); Текст.ИзЧЦел('" на строке %d.^Причина: ',строка,0,0,0,текст); Вывод.Цепь(текст); ВЫБРАТЬ код ИЗ | пределыАвОст: текст:='выход значения за допустимые пределы' | номерАвОст: текст:='неверный номер переменной ряда' | арифмАвОст: текст:='арифметическое переполнение' | охранаАвОст: текст:='неверный размещённый вид' | пустоАвОст: текст:='значение доступа "ПУСТО"' | дляАвОст: текст:='у "ДЛЯ" нет "ИНАЧЕ"' | выбратьАвОст: текст:='у "ВЫБРАТЬ" нет "ИНАЧЕ"' | ответАвОст: текст:='не определён ответ' | проверитьАвОст:текст:='"ПРОВЕРИТЬ" выдаёт ошибку' | нольАвОст: текст:='деление на ноль' | бегунокАвОст: текст:='бегунок вне ряда' ИНАЧЕ Текст.ИзЧЦел('код %d',код,0,0,0,текст) КОН; Вывод.Цепь(текст); Вывод.Цепь('.^Подробности см. в файле "Срез.пер".^'); поток:=Писать.Открыть("Срез.пер"); поток.видЗнаков:=Писать.знУни; Цепь(текст); ПерСтека(EBP); Писать.Закрыть(поток); СТОП(код) КОН Ловушка; (******************************************************************************) УКАЗ уборка:=ВКЛ КОН СРЕДА. |
▲ Вопросы, замечания и предложения высылайте на atimopheyev@yahoo.com
|
|